﻿/************************************************************************

 This file is part of EscapeFromPrisonPlanet.

 EscapeFromPrisonPlanet is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 EscapeFromPrisonPlanet is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

************************************************************************/

// All code (c)2012 Scott Bevin. all rights reserved

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace LudumDare25Project.Objects
{
    internal class StarryBackground
    {
        private class Star
        {
            public Vector2 Position;
            public Texture2D Sprite;
            public float Scale = 1.0f;
            public float BaseScale = 1.0f;
            public float Radius = 0.0f;
            public float Timer = 0.0f;
            public float Rotation = 0.0f;
            public float RotDirections = 0.0f;
            public bool DontScale = false;
        }

        private Vector2 ScreenSize;

        private List<Texture2D> bigStars = new List<Texture2D>();
        private List<Texture2D> smallStars = new List<Texture2D>();

        private List<Star> stars = new List<Star>();

        private Random rnd = new Random();

        private float TooFar = 2000.0f;

        public StarryBackground(ContentManager content, Vector2 screenSize)
        {
            ScreenSize = screenSize;

            LoadBigStars(content);
            LoadSmallStars(content);

            InitialiseStars(screenSize);

            Star earth = new Star();
            earth.Position = new Vector2(screenSize.X + 300.0f, ScreenSize.Y * 0.5f);
            earth.Sprite = content.Load<Texture2D>("Img/Planets/Earth");
            earth.DontScale = true;
            stars.Add(earth);

            Star goat = new Star();
            goat.Position = new Vector2(screenSize.X + 1000.0f, RandomFloat(100.0f, screenSize.Y - 100.0f));
            goat.Sprite = content.Load<Texture2D>("Img/Planets/SpaceGoat");
            goat.DontScale = true;
            goat.RotDirections = rnd.Next(100) < 50 ? -10.0f : 10.0f;
            stars.Add(goat);
        }

        private void LoadBigStars(ContentManager content)
        {
            bool done = false;
            int counter = 1;

            while (!done)
            {
                try
                {
                    Texture2D tex = content.Load<Texture2D>("Img/Stars/BigStar" + counter.ToString());
                    bigStars.Add(tex);
                    counter++;
                }
                catch (Exception e)
                {
                    done = true;
                }
            }
        }

        private void LoadSmallStars(ContentManager content)
        {
            bool done = false;
            int counter = 1;

            while (!done)
            {
                try
                {
                    Texture2D tex = content.Load<Texture2D>("Img/Stars/SmallStar" + counter.ToString());
                    smallStars.Add(tex);
                    counter++;
                }
                catch (Exception e)
                {
                    done = true;
                }
            }
        }

        private void InitialiseStars(Vector2 screenSize)
        {
            for (int i = 0; i < 50; ++i)
                CreateNewStar(screenSize, null);
        }

        public void Update(float dt, Vector2 focusPosition, Camera cam)
        {
            for (int i = 0; i < stars.Count; ++i)
            {
                Star star = stars[i];
                star.Timer += dt;
                if (!star.DontScale)
                    star.Scale = star.BaseScale + ((float)Math.Sin(star.Timer) * 0.1f);
                star.Rotation += dt * 0.2f * star.RotDirections;
                star.Position.X -= dt * 2.5f;

                if (star.Position.X < -200.0f)
                {
                    if (rnd.Next(0, 100) < 10)
                        star.Sprite = bigStars[rnd.Next(bigStars.Count)];
                    else
                        star.Sprite = smallStars[rnd.Next(bigStars.Count)];

                    star.DontScale = false;
                    star.Rotation = RandomFloat(0.0f, (float)MathHelper.TwoPi);
                    star.Timer = RandomFloat(0.0f, 10.0f);
                    star.Scale = RandomFloat(0.5f, 0.8f);

                    star.Position = new Vector2(
                        ScreenSize.X + 200.0f,
                        RandomFloat(0.0f, ScreenSize.Y));
                }
            }

            /*for (int i = 0; i < stars.Count; )
            {
                if ((stars[i].Position - focusPosition).LengthSquared() > TooFar * TooFar)
                {
                    stars.RemoveAt(i);
                }
                else
                {
                    ++i;
                }
            }

            int NotEnough = 10;

            if (stars.Count < NotEnough)
            {
                CreateNewStar(focusPosition, cam);
            }*/

#if DEBUG
            DebugDraw.Get.AddText( "Starry Background: " + stars.Count.ToString() );
#endif
        }

        private void CreateNewStar(Vector2 screenSize, Camera cam)
        {
            Star newStar = new Star();

            if (rnd.Next(0, 100) < 10)
                newStar.Sprite = bigStars[rnd.Next(bigStars.Count)];
            else
                newStar.Sprite = smallStars[rnd.Next(bigStars.Count)];

            newStar.Rotation = RandomFloat(0.0f, (float)MathHelper.TwoPi);
            newStar.Timer = RandomFloat(0.0f, 10.0f);
            newStar.Scale = RandomFloat(0.5f, 0.8f);
            newStar.BaseScale = newStar.Scale;
            newStar.Radius = ((float)Math.Sqrt((double)(newStar.Sprite.Width * newStar.Sprite.Width) +
                (double)(newStar.Sprite.Height * newStar.Sprite.Height))) * newStar.Scale;
            newStar.RotDirections = rnd.Next(100) < 50 ? -1.0f : 1.0f;

            bool found = false;
            int emergencyExit = 10;

            Vector2 pos = Vector2.Zero;

            pos = new Vector2(
                RandomFloat(0.0f, screenSize.X + 200.0f),
                RandomFloat(0.0f, screenSize.Y));

            /*while (!found)
            {
                --emergencyExit;

                if (emergencyExit <= 0)
                    return;

                pos = new Vector2(
                    RandomFloat(0.0f, screenSize.X),
                    RandomFloat(0.0f, screenSize.Y));

                // Onscreen?
                if (cam != null && cam.ClipTest(pos, newStar.Radius))
                    continue;

                // Too close to another star?
                bool safe = true;
                for (int i = 0; i < stars.Count; ++i )
                {
                    if ((stars[i].Position - pos).LengthSquared() < stars[i].Radius + newStar.Radius )
                    {
                        safe = false;
                        break;
                    }
                }

                found = safe;
            }*/

            newStar.Position = pos;
            stars.Add(newStar);
        }

        public float RandomFloat(float min, float max)
        {
            return min + (max - min) * (float)rnd.NextDouble();
        }

        public void Render(SpriteBatch sprites, Camera cam)
        {
            //sprites.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default,
            //   RasterizerState.CullNone, null, cam.WorldMatrix);

            sprites.Begin();

            foreach (Star star in stars)
            {
                sprites.Draw(
                    star.Sprite,
                    star.Position,
                    null,
                    Color.White,
                    star.Rotation,
                    new Vector2(star.Sprite.Width, star.Sprite.Height) * 0.5f,
                    star.Scale,
                    SpriteEffects.None,
                    0.0f);
            }

            sprites.End();
        }
    }
}